/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#ifndef jit_BaselineFrame_h#define jit_BaselineFrame_h#include"jit/JitFrames.h"#include"vm/Stack.h"namespacejs{namespacejit{structBaselineDebugModeOSRInfo;// The stack looks like this, fp is the frame pointer://// fp+y arguments// fp+x JitFrameLayout (frame header)// fp => saved frame pointer// fp-x BaselineFrame// locals// stack valuesclassBaselineFrame{public:enumFlags:uint32_t{// The frame has a valid return value. See also InterpreterFrame::HAS_RVAL.HAS_RVAL=1<<0,// An initial environment has been pushed on the environment chain for// function frames that need a CallObject or eval frames that need a// VarEnvironmentObject.HAS_INITIAL_ENV=1<<2,// Frame has an arguments object, argsObj_.HAS_ARGS_OBJ=1<<4,// See InterpreterFrame::PREV_UP_TO_DATE.PREV_UP_TO_DATE=1<<5,// Frame has execution observed by a Debugger.//// See comment above 'isDebuggee' in jscompartment.h for explanation of// invariants of debuggee compartments, scripts, and frames.DEBUGGEE=1<<6,// (1 << 7 and 1 << 8 are unused)// Frame has over-recursed on an early check.OVER_RECURSED=1<<9,// Frame has a BaselineRecompileInfo stashed in the scratch value// slot. See PatchBaselineFramesForDebugMode.HAS_DEBUG_MODE_OSR_INFO=1<<10,// This flag is intended for use whenever the frame is settled on a// native code address without a corresponding ICEntry. In this case,// the frame contains an explicit bytecode offset for frame iterators.//// There can also be an override pc if the frame has had its// environment chain unwound to a pc during exception handling that is// different from its current pc.//// This flag should never be set when we're executing JIT code.HAS_OVERRIDE_PC=1<<11,// If set, we're handling an exception for this frame. This is set for// debug mode OSR sanity checking when it handles corner cases which// only arise during exception handling.HANDLING_EXCEPTION=1<<12,// If set, this frame has been on the stack when// |js::SavedStacks::saveCurrentStack| was called, and so there is a// |js::SavedFrame| object cached for this frame.HAS_CACHED_SAVED_FRAME=1<<13};protected:// Silence Clang warning about unused private fields.// We need to split the Value into 2 fields of 32 bits, otherwise the C++// compiler may add some padding between the fields.union{struct{uint32_tloScratchValue_;uint32_thiScratchValue_;};BaselineDebugModeOSRInfo*debugModeOSRInfo_;};uint32_tloReturnValue_;// If HAS_RVAL, the frame's return value.uint32_thiReturnValue_;uint32_tframeSize_;JSObject*envChain_;// Environment chain (always initialized).ArgumentsObject*argsObj_;// If HAS_ARGS_OBJ, the arguments object.uint32_toverrideOffset_;// If HAS_OVERRIDE_PC, the bytecode offset.uint32_tflags_;public:// Distance between the frame pointer and the frame header (return address).// This is the old frame pointer saved in the prologue.staticconstuint32_tFramePointerOffset=sizeof(void*);MOZ_MUST_USEboolinitForOsr(InterpreterFrame*fp,uint32_tnumStackValues);uint32_tframeSize()const{returnframeSize_;}voidsetFrameSize(uint32_tframeSize){frameSize_=frameSize;}inlineuint32_t*addressOfFrameSize(){return&frameSize_;}JSObject*environmentChain()const{returnenvChain_;}voidsetEnvironmentChain(JSObject*envChain){envChain_=envChain;}inlineJSObject**addressOfEnvironmentChain(){return&envChain_;}inlineValue*addressOfScratchValue(){returnreinterpret_cast<Value*>(&loScratchValue_);}template<typenameSpecificEnvironment>inlinevoidpushOnEnvironmentChain(SpecificEnvironment&env);template<typenameSpecificEnvironment>inlinevoidpopOffEnvironmentChain();inlinevoidreplaceInnermostEnvironment(EnvironmentObject&env);CalleeTokencalleeToken()const{uint8_t*pointer=(uint8_t*)this+Size()+offsetOfCalleeToken();return*(CalleeToken*)pointer;}voidreplaceCalleeToken(CalleeTokentoken){uint8_t*pointer=(uint8_t*)this+Size()+offsetOfCalleeToken();*(CalleeToken*)pointer=token;}boolisConstructing()const{returnCalleeTokenIsConstructing(calleeToken());}JSScript*script()const{returnScriptFromCalleeToken(calleeToken());}JSFunction*callee()const{returnCalleeTokenToFunction(calleeToken());}Valuecalleev()const{returnObjectValue(*callee());}size_tnumValueSlots()const{size_tsize=frameSize();MOZ_ASSERT(size>=BaselineFrame::FramePointerOffset+BaselineFrame::Size());size-=BaselineFrame::FramePointerOffset+BaselineFrame::Size();MOZ_ASSERT((size%sizeof(Value))==0);returnsize/sizeof(Value);}Value*valueSlot(size_tslot)const{MOZ_ASSERT(slot<numValueSlots());return(Value*)this-(slot+1);}Value&unaliasedFormal(unsignedi,MaybeCheckAliasingcheckAliasing=CHECK_ALIASING)const{MOZ_ASSERT(i<numFormalArgs());MOZ_ASSERT_IF(checkAliasing,!script()->argsObjAliasesFormals()&&!script()->formalIsAliased(i));returnargv()[i];}Value&unaliasedActual(unsignedi,MaybeCheckAliasingcheckAliasing=CHECK_ALIASING)const{MOZ_ASSERT(i<numActualArgs());MOZ_ASSERT_IF(checkAliasing,!script()->argsObjAliasesFormals());MOZ_ASSERT_IF(checkAliasing&&i<numFormalArgs(),!script()->formalIsAliased(i));returnargv()[i];}Value&unaliasedLocal(uint32_ti)const{MOZ_ASSERT(i<script()->nfixed());return*valueSlot(i);}unsignednumActualArgs()const{return*(size_t*)(reinterpret_cast<constuint8_t*>(this)+BaselineFrame::Size()+offsetOfNumActualArgs());}unsignednumFormalArgs()const{returnscript()->functionNonDelazifying()->nargs();}Value&thisArgument()const{MOZ_ASSERT(isFunctionFrame());return*(Value*)(reinterpret_cast<constuint8_t*>(this)+BaselineFrame::Size()+offsetOfThis());}Value*argv()const{return(Value*)(reinterpret_cast<constuint8_t*>(this)+BaselineFrame::Size()+offsetOfArg(0));}private:Value*evalNewTargetAddress()const{MOZ_ASSERT(isEvalFrame());MOZ_ASSERT(script()->isDirectEvalInFunction());return(Value*)(reinterpret_cast<constuint8_t*>(this)+BaselineFrame::Size()+offsetOfEvalNewTarget());}public:ValuenewTarget()const{if(isEvalFrame())return*evalNewTargetAddress();MOZ_ASSERT(isFunctionFrame());if(callee()->isArrow())returncallee()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);if(isConstructing()){return*(Value*)(reinterpret_cast<constuint8_t*>(this)+BaselineFrame::Size()+offsetOfArg(Max(numFormalArgs(),numActualArgs())));}returnUndefinedValue();}boolhasReturnValue()const{returnflags_&HAS_RVAL;}MutableHandleValuereturnValue(){if(!hasReturnValue())addressOfReturnValue()->setUndefined();returnMutableHandleValue::fromMarkedLocation(addressOfReturnValue());}voidsetReturnValue(constValue&v){returnValue().set(v);flags_|=HAS_RVAL;}inlineValue*addressOfReturnValue(){returnreinterpret_cast<Value*>(&loReturnValue_);}boolhasInitialEnvironment()const{returnflags_&HAS_INITIAL_ENV;}inlineCallObject&callObj()const;voidsetFlags(uint32_tflags){flags_=flags;}uint32_t*addressOfFlags(){return&flags_;}inlineMOZ_MUST_USEboolpushLexicalEnvironment(JSContext*cx,Handle<LexicalScope*>scope);inlineMOZ_MUST_USEboolfreshenLexicalEnvironment(JSContext*cx);inlineMOZ_MUST_USEboolrecreateLexicalEnvironment(JSContext*cx);MOZ_MUST_USEboolinitFunctionEnvironmentObjects(JSContext*cx);MOZ_MUST_USEboolpushVarEnvironment(JSContext*cx,HandleScopescope);voidinitArgsObjUnchecked(ArgumentsObject&argsobj){flags_|=HAS_ARGS_OBJ;argsObj_=&argsobj;}voidinitArgsObj(ArgumentsObject&argsobj){MOZ_ASSERT(script()->needsArgsObj());initArgsObjUnchecked(argsobj);}boolhasArgsObj()const{returnflags_&HAS_ARGS_OBJ;}ArgumentsObject&argsObj()const{MOZ_ASSERT(hasArgsObj());MOZ_ASSERT(script()->needsArgsObj());return*argsObj_;}boolprevUpToDate()const{returnflags_&PREV_UP_TO_DATE;}voidsetPrevUpToDate(){flags_|=PREV_UP_TO_DATE;}voidunsetPrevUpToDate(){flags_&=~PREV_UP_TO_DATE;}boolisDebuggee()const{returnflags_&DEBUGGEE;}voidsetIsDebuggee(){flags_|=DEBUGGEE;}inlinevoidunsetIsDebuggee();boolisHandlingException()const{returnflags_&HANDLING_EXCEPTION;}voidsetIsHandlingException(){flags_|=HANDLING_EXCEPTION;}voidunsetIsHandlingException(){flags_&=~HANDLING_EXCEPTION;}boolhasCachedSavedFrame()const{returnflags_&HAS_CACHED_SAVED_FRAME;}voidsetHasCachedSavedFrame(){flags_|=HAS_CACHED_SAVED_FRAME;}booloverRecursed()const{returnflags_&OVER_RECURSED;}voidsetOverRecursed(){flags_|=OVER_RECURSED;}BaselineDebugModeOSRInfo*debugModeOSRInfo(){MOZ_ASSERT(flags_&HAS_DEBUG_MODE_OSR_INFO);returndebugModeOSRInfo_;}BaselineDebugModeOSRInfo*getDebugModeOSRInfo(){if(flags_&HAS_DEBUG_MODE_OSR_INFO)returndebugModeOSRInfo();returnnullptr;}voidsetDebugModeOSRInfo(BaselineDebugModeOSRInfo*info){flags_|=HAS_DEBUG_MODE_OSR_INFO;debugModeOSRInfo_=info;}voiddeleteDebugModeOSRInfo();// See the HAS_OVERRIDE_PC comment.boolhasOverridePc()const{returnflags_&HAS_OVERRIDE_PC;}jsbytecode*overridePc()const{MOZ_ASSERT(hasOverridePc());returnscript()->offsetToPC(overrideOffset_);}jsbytecode*maybeOverridePc()const{if(hasOverridePc())returnoverridePc();returnnullptr;}voidsetOverridePc(jsbytecode*pc){flags_|=HAS_OVERRIDE_PC;overrideOffset_=script()->pcToOffset(pc);}voidclearOverridePc(){flags_&=~HAS_OVERRIDE_PC;}voidtrace(JSTracer*trc,JitFrameIterator&frame);boolisGlobalFrame()const{returnscript()->isGlobalCode();}boolisModuleFrame()const{returnscript()->module();}boolisEvalFrame()const{returnscript()->isForEval();}boolisStrictEvalFrame()const{returnisEvalFrame()&&script()->strict();}boolisNonStrictEvalFrame()const{returnisEvalFrame()&&!script()->strict();}boolisNonGlobalEvalFrame()const;boolisNonStrictDirectEvalFrame()const{returnisNonStrictEvalFrame()&&isNonGlobalEvalFrame();}boolisFunctionFrame()const{returnCalleeTokenIsFunction(calleeToken());}boolisDebuggerEvalFrame()const{returnfalse;}JitFrameLayout*framePrefix()const{uint8_t*fp=(uint8_t*)this+Size()+FramePointerOffset;return(JitFrameLayout*)fp;}// Methods below are used by the compiler.staticsize_toffsetOfCalleeToken(){returnFramePointerOffset+js::jit::JitFrameLayout::offsetOfCalleeToken();}staticsize_toffsetOfThis(){returnFramePointerOffset+js::jit::JitFrameLayout::offsetOfThis();}staticsize_toffsetOfEvalNewTarget(){returnFramePointerOffset+js::jit::JitFrameLayout::offsetOfEvalNewTarget();}staticsize_toffsetOfArg(size_tindex){returnFramePointerOffset+js::jit::JitFrameLayout::offsetOfActualArg(index);}staticsize_toffsetOfNumActualArgs(){returnFramePointerOffset+js::jit::JitFrameLayout::offsetOfNumActualArgs();}staticsize_tSize(){returnsizeof(BaselineFrame);}// The reverseOffsetOf methods below compute the offset relative to the// frame's base pointer. Since the stack grows down, these offsets are// negative.staticintreverseOffsetOfFrameSize(){return-int(Size())+offsetof(BaselineFrame,frameSize_);}staticintreverseOffsetOfScratchValue(){return-int(Size())+offsetof(BaselineFrame,loScratchValue_);}staticintreverseOffsetOfEnvironmentChain(){return-int(Size())+offsetof(BaselineFrame,envChain_);}staticintreverseOffsetOfArgsObj(){return-int(Size())+offsetof(BaselineFrame,argsObj_);}staticintreverseOffsetOfFlags(){return-int(Size())+offsetof(BaselineFrame,flags_);}staticintreverseOffsetOfReturnValue(){return-int(Size())+offsetof(BaselineFrame,loReturnValue_);}staticintreverseOffsetOfLocal(size_tindex){return-int(Size())-(index+1)*sizeof(Value);}};// Ensure the frame is 8-byte aligned (required on ARM).JS_STATIC_ASSERT(((sizeof(BaselineFrame)+BaselineFrame::FramePointerOffset)%8)==0);}// namespace jit}// namespace js#endif /* jit_BaselineFrame_h */